package com.pansoft.openplanet.util;


import com.pansoft.openplanet.account.model.BchGeneratorBean;

import org.bitcoincashj.core.Address;
import org.bitcoincashj.core.CashAddress;
import org.bitcoincashj.core.CashAddressFactory;
import org.bitcoincashj.core.CashAddressHelper;
import org.bitcoincashj.core.ECKey;
import org.bitcoincashj.crypto.ChildNumber;
import org.bitcoincashj.crypto.DeterministicKey;
import org.bitcoincashj.crypto.HDKeyDerivation;
import org.bitcoincashj.wallet.DeterministicSeed;
import org.bitcoincashj.wallet.Wallet;
import org.web3j.utils.Numeric;

import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Bch 助记词，恢复相关工具类
 * @author will
 */
public class BchMnemonicUtils {

    /**
     * 通用的比特币基于bip44协议的助记词路径 （imtoken jaxx Metamask myetherwallet）
     */
    //private static String BTC_TYPE = "m/44'/0'/0'/0/0";
    private static String BTC_TYPE = "m/0'/0/0";
    private static SecureRandom secureRandom = new SecureRandom();

    /**
     * 使用密码生成助记词（暂未用到密码）
     *
     * @param password password 为空
     * @return seed
     */
    public static DeterministicSeed generateMnemonic(String password) {
        if (!BTC_TYPE.startsWith("m") && !BTC_TYPE.startsWith("M")) {
            //参数非法
            return null;
        }
        String[] pathArray = BTC_TYPE.split("/");
        if (pathArray.length <= 1) {
            //内容不对
            return null;
        }
        String passphrase = "";
        long creationTimeSeconds = System.currentTimeMillis() / 1000;
        DeterministicSeed ds = new DeterministicSeed(secureRandom, 128, passphrase, creationTimeSeconds);
        //种子
        byte[] seedBytes = ds.getSeedBytes();
//        Log.i(TAG, "createRandomDeterministicSeed: "+Arrays.toString(seedBytes));
        System.out.println("createRandomDeterministicSeed: " + Arrays.toString(seedBytes));
        //助记词
        List<String> mnemonic = ds.getMnemonicCode();
//        Log.i(TAG, "createRandomDeterministicSeed: "+Arrays.toString(mnemonic.toArray()));
        System.out.println("createRandomDeterministicSeed: " + Arrays.toString(mnemonic.toArray()));
        return ds;
    }

    /**
     * 使用助记词种子生成钱包
     *
     * @param ds seed
     * @return key
     */
    public static ECKey generateECKey(DeterministicSeed ds) {
        //todo 方法1
        DeterministicKey deterministicKey = HDKeyDerivation.createMasterPrivateKey(ds.getSeedBytes());
        String[] pathArray = BTC_TYPE.split("/");
        for (int i = 1; i < pathArray.length; i++) {
            ChildNumber childNumber;
            if (pathArray[i].endsWith("'")) {
                int number = Integer.parseInt(pathArray[i].substring(0,
                        pathArray[i].length() - 1));
                childNumber = new ChildNumber(number, true);
            } else {
                int number = Integer.parseInt(pathArray[i]);
                childNumber = new ChildNumber(number, false);
            }
            deterministicKey = HDKeyDerivation.deriveChildKey(deterministicKey, childNumber);
        }
        //  ECKey ecKey= ECKey.fromPrivate(deterministicKey.getPrivKeyBytes());


        //todo 方法2(不正确)
//        DeterministicKeyChain deterministicKeyChain = DeterministicKeyChain.builder().seed(ds).build();
//        //这里运用了BIP44里面提到的算法, 44'是固定的, 后面的一个0'代表的是币种BTC
//        List<ChildNumber> keyPath = HDUtils.parsePath("M/44/0/0/0/0");
//
//        DeterministicKey deterministicKey = deterministicKeyChain.getKeyByPath(keyPath, true);

        //todo 方式1获取公钥私钥（16进制）
//        System.out.println(deterministicKey.getPrivateKeyAsHex());
//        System.out.println(deterministicKey.getPublicKeyAsHex());

        //todo 方式2获取公钥私钥
        BigInteger privKeyBTC = deterministicKey.getPrivKey();
        ECKey ecKey = ECKey.fromPrivate(privKeyBTC);

        String publickey = Numeric.toHexStringNoPrefixZeroPadded(new BigInteger(ecKey.getPubKey()), 66);
        //正式环境应该是主网参数
        String privateKey = ecKey.getPrivateKeyEncoded(BchNetParamUtil.getBtcNetParams()).toString();

        System.out.println(privateKey);
        System.out.println(publickey);
//        System.out.println("ecKey.toAddress:" + ecKey.toAddress(BtcNetParamUtil.getBtcNetParams()));

        Address myAddress = ecKey.toAddress(BchNetParamUtil.getBtcNetParams());
        System.out.println("ecKey.toAddress:" + myAddress);




        return ecKey;
    }

    public static void main(String[] args) {
        // DeterministicSeed ds = createRandomDeterministicSeed("");
        // generateECKey(ds);
        //generateECKey2(ds);
        try {
//           restoreByMnemonic("chief invest small suffer manage sure people account lonely cousin vibrant can", "");
            // restoreByMnemonic("awkward decorate lunar fancy foster write taxi column family derive tattoo absent", "");

//            restoreByMnemonic("chief invest small suffer manage sure people account lonely cousin vibrant can", "");
//            restoreByPrivateKey("KyCfRAJiTpbhVnALqRy2MafcM8shNnnYddUnKqpRqBL5DficNK6v","");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 使用助记词和密码生成钱包文件
     *
     * @param mnemonic 助记词
     * @param passWord 密码(密码现在使用"")
     * @return
     * @throws Exception
     */
    public static BchGeneratorBean restoreByMnemonic(String mnemonic, String passWord) throws Exception {
        String[] array = mnemonic.split(" ");
        if (array == null || array.length != 12) {
            throw new Exception("助记词错误");
        }
        List<String> list = new ArrayList<>();
        for (int i = 0; i < array.length; i++) {
            list.add(array[i]);
        }
        long creationTimeSeconds = System.currentTimeMillis() / 1000;
        //种子
        DeterministicSeed ds = new DeterministicSeed(list, null, passWord, creationTimeSeconds);
        //生成钱包
        Wallet restoredWallet = Wallet.fromSeed(BchNetParamUtil.getBtcNetParams(), ds);
        //获取deterministicKey
        DeterministicKey deterministicKey = restoredWallet.currentReceiveKey();
        System.out.println("deterministicKey:" + deterministicKey);

        BigInteger privKeyBTC = deterministicKey.getPrivKey();
        //生成eckey
        ECKey ecKey = ECKey.fromPrivate(privKeyBTC);
        //公钥
//        String publickey = Numeric.toHexStringNoPrefixZeroPadded(new BigInteger(ecKey.getPubKey()), 66);
        String publickey = ecKey.getPublicKeyAsHex();
        //私钥
//        String privateKey = ecKey.getPrivateKeyEncoded(BtcNetParamUtil.getBtcNetParams()).toString();
        String privateKey = ecKey.getPrivateKeyAsWiF(BchNetParamUtil.getBtcNetParams()).toString();
        //地址
        String btcAddress= restoredWallet.currentReceiveAddress().toString();

        System.out.println("privateKey:" + privateKey);
        System.out.println("publickey:" + publickey);
        System.out.println("currentReceiveAddress:" + restoredWallet.currentReceiveAddress());
        //System.out.println("ecKey.toAddress:" + ecKey.toString(BtcNetParamUtil.getBtcNetParams()));

        // FIXME: 18-9-5 bch 地址
        Address bchAddress = CashAddressFactory.create().getFromBase58(BchNetParamUtil.getBtcNetParams(), btcAddress);
//        Address myAddress = ecKey.toAddress(BchNetParamUtil.getBtcNetParams());
        System.out.println("bchAddress:" + bchAddress);

        BchGeneratorBean bchBean = new BchGeneratorBean();
        bchBean.setWalletAddress(bchAddress.toString());
//        bchBean.setWalletAddress(btcAddress);
        bchBean.setPrivateKey(privateKey);
        bchBean.setPublicKey(publickey);
        bchBean.setWallet(restoredWallet);

        return bchBean;
    }
}
